package com.yupi.yuaicodemother.core.handler;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yupi.yuaicodemother.ai.model.message.*;
import com.yupi.yuaicodemother.ai.tools.BaseTool;
import com.yupi.yuaicodemother.ai.tools.ToolManager;
import com.yupi.yuaicodemother.core.builder.VueProjectBuilder;
import com.yupi.yuaicodemother.model.entity.User;
import com.yupi.yuaicodemother.model.enums.ChatHistoryMessageTypeEnum;
import com.yupi.yuaicodemother.service.ChatHistoryService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.HashSet;

/**
 * JSON 消息流处理器
 * 处理 VUE_PROJECT 类型的复杂流式响应，包含工具调用信息
 */
@Component
@Slf4j
public class JsonMessageStreamHandler {

    @Resource
    private VueProjectBuilder vueProjectBuilder;

    @Resource
    private ToolManager toolManager;

    /**
     * 处理 TokenStream（VUE_PROJECT）
     * 解析 JSON 消息并重组为完整的响应格式
     *
     * @param originFlux         原始流
     * @param chatHistoryService 聊天历史服务
     * @param appId              应用ID
     * @param loginUser          登录用户
     * @return 处理后的流
     */
    public Flux<String> handle(Flux<String> originFlux,
                               ChatHistoryService chatHistoryService,
                               long appId,
                               User loginUser){

        // 定义拼接器: 收集数据用于生成后端记忆格式
        StringBuilder chatHistoryStringBuilder = new StringBuilder();

        // 用于跟踪已经见过的工具ID，判断是否是第一次调用
        HashSet<String> seenToolIds = new HashSet<>();

        // 处理流
        return originFlux
                .map(chunk -> {
                    // 解析每一个 JSON 块
                    return handleJsonMessageChunk(chunk, chatHistoryStringBuilder, seenToolIds);
                })
                .onErrorContinue((error, chunk) -> {
                    // 即使某个块处理失败，也继续处理后续块
                    log.error("处理流消息块时发生异常，跳过该块: {}", chunk, error);
                })
                .doOnComplete(() -> {
                    String aiResponse = chatHistoryStringBuilder.toString();
                    chatHistoryService.addChatMessage(appId, aiResponse,
                            ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId());

                    // 异步构造 Vue 项目 (后期修改为同步构造)
//                    String projectPath = AppConstant.CODE_OUTPUT_ROOT_DIR + "/vue_project_" + appId;
//                    vueProjectBuilder.buildProjectAsync(projectPath);
                })
                .doOnError(error -> {
                    String errMessage = "AI 回复失败：" + error.getMessage();
                    log.error("流处理发生严重错误", error);
                    chatHistoryService.addChatMessage(appId, errMessage,
                            ChatHistoryMessageTypeEnum.AI.getValue(), loginUser.getId());
                });
    }

    /**
     * 解析并收集 TokenStream 数据
     */
    private String handleJsonMessageChunk(String chunk, StringBuilder chatHistoryStringBuilder, HashSet<String> seenToolIds) {
        try {
            // 解析 JSON
            StreamMessage streamMessage = JSONUtil.toBean(chunk, StreamMessage.class);
            if (streamMessage == null || streamMessage.getType() == null) {
                log.warn("无法解析流消息或消息类型为空: {}", chunk);
                return "";
            }

            // 获取流对象的消息、消息类型 (AI 回复、选择工具、工具调用结果)
            StreamMessageTypeEnum typeEnum = StreamMessageTypeEnum.getEnumByValue(streamMessage.getType());
            if (typeEnum == null) {
                log.warn("不支持的消息类型: {}", streamMessage.getType());
                return "";
            }

            // 根据消息类型处理
            switch (typeEnum){
                case AI_RESPONSE -> {
                    AiResponseMessage aiMessage = JSONUtil.toBean(chunk, AiResponseMessage.class);
                    if (aiMessage == null || aiMessage.getData() == null) {
                        log.warn("AI响应消息解析失败: {}", chunk);
                        return "";
                    }
                    // AI 回复, 拼接并返回消息
                    String data = aiMessage.getData();
                    chatHistoryStringBuilder.append(data);
                    return data;
                }
                case TOOL_REQUEST -> {
                    ToolRequestMessage toolRequestMessage = JSONUtil.toBean(chunk, ToolRequestMessage.class);
                    if (toolRequestMessage == null) {
                        log.warn("工具请求消息解析失败: {}", chunk);
                        return "";
                    }
                    // 检查是否是第一次调用该工具
                    String toolId = toolRequestMessage.getId();
                    String toolName = toolRequestMessage.getName();
                    if(toolId != null && !seenToolIds.contains(toolId)){
                        // 第一次调用这个工具，记录 ID 并完整返回工具信息
                        seenToolIds.add(toolId);

                        // 根据 AI 要调用的工具名, 调用工具
                        BaseTool tool = toolManager.getTool(toolName);
                        if (tool == null) {
                            log.warn("未找到工具: {}, 工具ID: {}", toolName, toolId);
                            return "";
                        }

                        // 返回格式化的工具调用信息
                        return tool.generateToolRequestResponse();
                    }else{
                        // 不是第一次调用这个工具，直接返回空
                        return "";
                    }
                }
                case TOOL_EXECUTED -> {
                    ToolExecutedMessage toolExecutedMessage = JSONUtil.toBean(chunk, ToolExecutedMessage.class);
                    if (toolExecutedMessage == null) {
                        log.warn("工具执行消息解析失败: {}", chunk);
                        return "";
                    }

                    // 从工具执行信息中, 获取调用的工具名
                    String toolName = toolExecutedMessage.getName();
                    if (toolName == null) {
                        log.warn("工具执行消息中工具名为空: {}", chunk);
                        return "";
                    }

                    // 获取工具执行信息中的参数, 转为 JSON
                    String arguments = toolExecutedMessage.getArguments();
                    JSONObject jsonObject;
                    try {
                        if (arguments != null && !arguments.trim().isEmpty()) {
                            // 尝试清洗和修复JSON格式
                            String cleanedArguments = cleanJsonString(arguments);
                            jsonObject = JSONUtil.parseObj(cleanedArguments);
                        } else {
                            jsonObject = new JSONObject();
                        }
                    } catch (Exception e) {
                        log.warn("工具参数JSON解析失败，使用空对象。原始参数: {}, 错误: {}", arguments, e.getMessage());
                        jsonObject = new JSONObject();
                    }

                    // 根据工具名称获取工具实例并生成相应的结果格式
                    BaseTool tool = toolManager.getTool(toolName);
                    if (tool == null) {
                        log.warn("未找到工具: {}", toolName);
                        // 即使找不到工具，也尝试返回基本信息
                        return String.format("\n\n[工具调用] 未知工具 %s\n\n", toolName);
                    }

                    String result = tool.generateToolExecutedResult(jsonObject);
                    if (result == null) {
                        log.warn("工具 {} 生成执行结果为空", toolName);
                        return "";
                    }

                    // 输出前端和要持久化的内容
                    String output = String.format("\n\n%s\n\n", result);
                    chatHistoryStringBuilder.append(output);
                    return output;
                }
                default -> {
                    log.error("不支持的消息类型: {}", typeEnum);
                    return "";
                }
            }
        } catch (Exception e) {
            log.error("处理流消息块时发生异常: {}", chunk, e);
            return "";
        }
    }

    /**
     * 清洗和修复JSON字符串
     * 尝试修复常见的JSON格式错误，如缺少逗号、引号不匹配等
     *
     * @param jsonString 原始JSON字符串
     * @return 清洗后的JSON字符串
     */
    private String cleanJsonString(String jsonString) {
        if (jsonString == null || jsonString.trim().isEmpty()) {
            return "{}";
        }

        String cleaned = jsonString.trim();

        // 如果字符串不是以 { 或 [ 开头，尝试提取JSON部分
        if (!cleaned.startsWith("{") && !cleaned.startsWith("[")) {
            // 查找第一个 { 或 [
            int startIndex = Math.max(cleaned.indexOf('{'), cleaned.indexOf('['));
            if (startIndex >= 0) {
                cleaned = cleaned.substring(startIndex);
            } else {
                // 如果没有找到，尝试包装为对象
                return "{}";
            }
        }

        // 移除JSON字符串末尾的非JSON字符
        int lastBrace = cleaned.lastIndexOf('}');
        int lastBracket = cleaned.lastIndexOf(']');
        int lastValidChar = Math.max(lastBrace, lastBracket);
        if (lastValidChar > 0 && lastValidChar < cleaned.length() - 1) {
            cleaned = cleaned.substring(0, lastValidChar + 1);
        }

        // 尝试修复常见的JSON格式错误
        // 1. 修复缺少逗号的情况（在 } 或 ] 后跟字母的情况）
        cleaned = cleaned.replaceAll("}([a-zA-Z])", "},\"$1");
        cleaned = cleaned.replaceAll("]([a-zA-Z])", "],\"$1");

        // 2. 移除多余的字符（在有效JSON之后）
        // 确保字符串以 } 或 ] 结尾
        if (!cleaned.endsWith("}") && !cleaned.endsWith("]")) {
            // 尝试找到最后一个完整的JSON结构
            int braceCount = 0;
            int bracketCount = 0;
            int lastValidIndex = -1;
            for (int i = 0; i < cleaned.length(); i++) {
                char c = cleaned.charAt(i);
                if (c == '{') braceCount++;
                else if (c == '}') braceCount--;
                else if (c == '[') bracketCount++;
                else if (c == ']') bracketCount--;

                if (braceCount == 0 && bracketCount == 0 && i > 0) {
                    lastValidIndex = i;
                }
            }
            if (lastValidIndex > 0) {
                cleaned = cleaned.substring(0, lastValidIndex + 1);
            }
        }

        // 如果清洗后为空或无效，返回空对象
        if (cleaned.trim().isEmpty() || (!cleaned.trim().startsWith("{") && !cleaned.trim().startsWith("["))) {
            return "{}";
        }

        return cleaned;
    }
}
